#include "EdgeMesh.hpp"
#include "MeshAlgorithm.hpp"
#include "EdgeMap.hpp"

using namespace MeshAlgorithm;
using namespace EdgeMeshData;


EdgeMesh::EdgeMesh(Mesh& aMesh)
{
   mEdgeCount = 0;
   EdgeMap edgeMap;
   mVerts = *aMesh.verts;
   mFaces.resize(aMesh.faces.size());
   for (size_t i = 0; i < aMesh.faces.size(); ++i)
   {
      Face& f = aMesh.faces[i]; 
      EdgeFace& ef = mFaces[i];
      ef.face = f;
      edgeMap.AddFace(f, ef.edges[0], ef.edges[1], ef.edges[2]);
      AddFaceEdgeP(i, ef.edges[0], f.vertex[0], f.vertex[1]);
      AddFaceEdgeP(i, ef.edges[1], f.vertex[1], f.vertex[2]);
      AddFaceEdgeP(i, ef.edges[2], f.vertex[2], f.vertex[0]);
   }
   mEdges.resize(mEdgeCount);
}
EdgeMesh::~EdgeMesh()
{
   for (size_t i = 0; i < mEdges.size(); ++i)
   {
      EdgeMeshData::EdgeEdge& e = mEdges[i];
      e.DeletePrivate();
   }
}
void EdgeMesh::AddFaceEdgeP(int aFace,
                            int aEdgeId,
                            int v1,
                            int v2)
{
   if (aEdgeId >= mEdgeCount) mEdgeCount = aEdgeId + 1;
   if ((int)mEdges.size() <= aEdgeId)
   {
      mEdges.resize(aEdgeId + 100);
   }
   mEdges[aEdgeId].AddFace(aFace);
   if (mEdges[aEdgeId].size() == 1)
   {
      mEdges[aEdgeId].verts[0] = v1;
      mEdges[aEdgeId].verts[1] = v2;
   }
}

void EdgeMesh::LinkFaceEdge(int aFace,
                            int aEdgeId)
{
   mEdges[aEdgeId].AddFace(aFace);
}

void EdgeMesh::GetMesh(Mesh& aMesh)
{
   aMesh.faces->resize(mFaces.size());
   *aMesh.verts = mVerts;
   for (size_t i = 0; i < mFaces.size(); ++i)
   {
      aMesh.faces[i] = mFaces[i].face;
   }
}

void EdgeMesh::SplitEdge(int               aEdgeId,
                         std::vector<int>& aNewEdges)
{
   //Check();
   EdgeEdge ee = mEdges[aEdgeId];
   ee.CopyPrivate();
   int newSplitId = mEdges.size();
   mEdges.push_back(EdgeMeshData::EdgeEdge());
   aNewEdges.push_back(newSplitId);
   int newVertId = mVerts.size();
   mVerts.push_back(Vec3());
   Vec3& newVert = mVerts[newVertId];
   
   for (int i = 0; i < ee.size(); ++i)
   {
      int newJoinId = mEdges.size();
      mEdges.push_back(EdgeMeshData::EdgeEdge());
      EdgeMeshData::EdgeEdge& newSplitEdge = mEdges[newSplitId];
      EdgeMeshData::EdgeEdge& newJoinEdge = mEdges[newJoinId];
      aNewEdges.push_back(newJoinId);

      int faceId = ee[i];
      EdgeFace& ef = mFaces[faceId];

      mEdges[ef.edges[0]].RemoveFace(faceId);
      mEdges[ef.edges[1]].RemoveFace(faceId);
      mEdges[ef.edges[2]].RemoveFace(faceId);
      int edgeIndex;
      if (ef.edges[0] == aEdgeId) edgeIndex = 0;
      else if (ef.edges[1] == aEdgeId) edgeIndex = 1;
      else edgeIndex = 2;
      if (i == 0)
      {
         int v1 = ef.face.vertex[edgeIndex];
         int v2 = ef.face.vertex[(edgeIndex + 1) % 3];
         newVert = (mVerts[v1] + mVerts[v2]) / 2.0f;
         newSplitEdge.verts[0] = newVertId;
         newSplitEdge.verts[1] = v2;
         EdgeEdge& ee = mEdges[aEdgeId];
         assert((ee.verts[0] == v1 || ee.verts[1] == v1)
            && (ee.verts[0] == v2 || ee.verts[1] == v2));
         
         if (ee.verts[0] == v1)
         {
            ee.verts[1] = newVertId;
         }
         else
         {
            ee.verts[0] = newVertId;
         }
      }
      newJoinEdge.verts[0] = newVertId;
      newJoinEdge.verts[1] = ef.face.vertex[(edgeIndex + 2)%3];
      EdgeFace newFaceA;
      EdgeFace newFaceB;
      if (newSplitEdge.verts[0] == ef.face.vertex[edgeIndex]
      || newSplitEdge.verts[1] == ef.face.vertex[edgeIndex])
      {
         //SplitFace(ef, edgeIndex, aEdgeId, newSplitId, newJoinId, newVertId, newFaceA, newFaceB);
         SplitFace(ef, edgeIndex, newSplitId, aEdgeId, newJoinId, newVertId, newFaceA, newFaceB);
      }
      else
      {
         //SplitFace(ef, edgeIndex, newSplitId, aEdgeId, newJoinId, newVertId, newFaceA, newFaceB);
         SplitFace(ef, edgeIndex, aEdgeId, newSplitId, newJoinId, newVertId, newFaceA, newFaceB);
      }
      //ef = newFaceA;
      mFaces[faceId] = newFaceA;
      int newFaceId = mFaces.size();
      mFaces.push_back(newFaceB);
      LinkFaceEdge(newFaceId, newFaceB.edges[0]);
      LinkFaceEdge(newFaceId, newFaceB.edges[1]);
      LinkFaceEdge(newFaceId, newFaceB.edges[2]);

      LinkFaceEdge(faceId, newFaceA.edges[0]);
      LinkFaceEdge(faceId, newFaceA.edges[1]);
      LinkFaceEdge(faceId, newFaceA.edges[2]);
   }
   ee.DeletePrivate();
   //Check();
}

void EdgeMesh::SplitFace(EdgeMeshData::EdgeFace& aFace,
                         int                     aSplitEdge,
                         int                     aSplitEdge1,
                         int                     aSplitEdge2,
                         int                     aNewEdge,
                         int                     aNewVertex,
                         EdgeMeshData::EdgeFace& aNewFaceA,
                         EdgeMeshData::EdgeFace& aNewFaceB)
{
   int ep1 = (aSplitEdge + 1) % 3;
   int ep2 = (aSplitEdge + 2) % 3;
   aNewFaceA.face.vertex[0] = aFace.face.vertex[aSplitEdge];
   aNewFaceA.face.vertex[1] = aNewVertex;
   aNewFaceA.face.vertex[2] = aFace.face.vertex[ep2];
   aNewFaceA.face.materials = aNewFaceB.face.materials = aFace.face.materials;
   aNewFaceB.face.vertex[0] = aNewVertex;
   aNewFaceB.face.vertex[1] = aFace.face.vertex[ep1];
   aNewFaceB.face.vertex[2] = aFace.face.vertex[ep2];

   aNewFaceA.edges[0] = aSplitEdge1;
   aNewFaceA.edges[1] = aNewEdge;
   aNewFaceA.edges[2] = aFace.edges[ep2];
   aNewFaceB.edges[0] = aSplitEdge2;
   aNewFaceB.edges[1] = aFace.edges[ep1];
   aNewFaceB.edges[2] = aNewEdge;
}
void EdgeMesh::Check()
{
   for (size_t i = 0; i < mEdges.size(); ++i)
   {
      if (mEdges[i].size() != 2)
      {
         assert(!"Bad face Count");
      }
      EdgeEdge& e = mEdges[i];

      int f1 = e[0];
      int f2 = e[1];
      bool f1ok=false, f2ok=false;
      for (int j = 0; j < 3; ++j)
      {
         if (mFaces[f1].edges[j] == i)
         {
            EdgeFace& ef = mFaces[f1];
            if (ef.face.vertex[j] == e.verts[0] && ef.face.vertex[(j+1)%3] == e.verts[1]
            || ef.face.vertex[j] == e.verts[1] && ef.face.vertex[(j+1)%3] == e.verts[0])
            {
               f1ok=true;
            }
            else
            {
               assert(!"Fail");
            }
         }
         if (mFaces[f2].edges[j] == i)
         {
            EdgeFace& ef = mFaces[f2];
            if (ef.face.vertex[j] == e.verts[0] && ef.face.vertex[(j+1)%3] == e.verts[1]
            || ef.face.vertex[j] == e.verts[1] && ef.face.vertex[(j+1)%3] == e.verts[0])
            {
               f2ok=true;
            }
            else
            {
               assert(!"Fail");
            }
         }
      }
      if (!f1ok || !f2ok) { assert(!"Bad edge connectivity"); }
   }
}

void EdgeMesh::SplitLargest()
{
   float maxSize = 0;
   int maxEdge = 0;
   for (size_t i = 0; i < mEdges.size(); ++i)
   {
      EdgeEdge& ee = mEdges[i];
      float len = (mVerts[ee.verts[0]] - mVerts[ee.verts[1]]).length_squared();
      if (len > maxSize)
      {
         maxSize = len;
         maxEdge = i;
      }
   }
   //SplitEdge(maxEdge);
}
